package fields

import (
	"database/sql/driver"
	"encoding/json"
	"github.com/zeebo/errs"
)

var Error = errs.Class("attr")

type Attribute map[string]string

func FromString(str string) (Attribute, error) {
	attr := Attribute{}
	if str == "" {
		return attr, nil
	}
	err := json.Unmarshal([]byte(str), &attr)
	return attr, err
}

func (attr Attribute) Get(string2 string) string {
	if ct, ok := attr[string2]; ok {
		return ct
	}
	return ""
}

func (attr Attribute) Set(key, val string) {
	attr[key] = val
}

func (attr Attribute) ContentType() string {
	return attr.Get("Content-Type")
}

func (attr Attribute) SetContentType(ct string) {
	attr.Set("Content-Type", ct)
}

func (attr Attribute) String() string {
	if attr == nil {
		return ""
	}
	res, _ := json.Marshal(attr)
	return string(res)
}

// Value implements sql/driver.Valuer interface.
func (attr Attribute) Value() (driver.Value, error) {
	return attr.String(), nil
}

// Scan implements sql.Scanner interface.
func (attr *Attribute) Scan(value interface{}) error {
	switch value := value.(type) {
	case []byte:
		var err error
		*attr, err = FromString(string(value))
		if err != nil {
			return Error.Wrap(err)
		}
		return nil
	case string:
		var err error
		*attr, err = FromString(value)
		if err != nil {
			return Error.Wrap(err)
		}
		return nil
	default:
		return Error.New("unable to scan %T into rs_coder", value)
	}
}

// NullUUID represents a UUID that may be null.
// NullUUID implements the Scanner interface so it can be used
// as a scan destination, similar to sql.NullString.
type NullAttribute struct {
	Attr  Attribute
	Valid bool // Valid is true if UUID is not NULL
}

// Value implements sql/driver.Valuer interface.
func (n NullAttribute) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	}
	return n.Attr.Value()
}

// Scan implements sql.Scanner interface.
func (n *NullAttribute) Scan(value interface{}) error {
	if value == nil {
		n.Attr, n.Valid = Attribute{}, false
		return nil
	}

	n.Valid = true
	return n.Attr.Scan(value)
}
